home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume25 / permissions / part01 next >
Encoding:
Text File  |  1992-03-23  |  45.9 KB  |  1,722 lines

  1. Newsgroups: comp.sources.unix
  2. From: deraadt@cpsc.ucalgary.ca (Theo Deraadt)
  3. Subject: v25i152: permissions - access control library for YP/NIS environments, Part01/03
  4. Sender: unix-sources-moderator@pa.dec.com
  5. Approved: vixie@pa.dec.com
  6.  
  7. Submitted-By: deraadt@cpsc.ucalgary.ca (Theo Deraadt)
  8. Posting-Number: Volume 25, Issue 152
  9. Archive-Name: permissions/part01
  10.  
  11. [ Permissions is a library for controlling access to machines and resources
  12.   in a network environment.  It uses YP for to store and access its database
  13.   of who has permission to do what.  Caveat: some people would argue that
  14.   YP and real "security" are orthogonal concepts.
  15.  
  16.   In order to really make use of the library, you will need to have
  17.   and to hack the source of the program (e.g., login.c) that you want to
  18.   have use the library.  This could pose a problem to many of you binary-only
  19.   people.  [ and the free BSD sources don't have YP in them... --vix ]
  20.  
  21.   Permissions was written by Theo Deraadt <deraadt@cpsc.ucalgary.ca>.
  22.  
  23.   --Nick ]
  24.  
  25. #! /bin/sh
  26. # This is a shell archive.  Remove anything before this line, then unpack
  27. # it by saving it into a file and typing "sh file".  To overwrite existing
  28. # files, type "sh file -c".  You can also feed this as standard input via
  29. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  30. # will see the following message at the end:
  31. #        "End of archive 1 (of 3)."
  32. # Contents:  Makefile README examples examples/cpsc.ucalgary.ca in.ftpd
  33. #   in.ftpd/Makefile in.ftpd/logwtmp.c in.ftpd/popen.c in.ftpd/vers.c
  34. #   in.rshd in.rshd/Makefile in.rshd/in.rshd.c login login/Makefile
  35. #   perms perms/Makefile perms/glob_match.c perms/perms.y permtest
  36. #   permtest/Makefile permtest/permtest.c
  37. # Wrapped by vixie@cognition.pa.dec.com on Tue Mar 10 23:11:20 1992
  38. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  39. if test -f 'Makefile' -a "${1}" != "-c" ; then 
  40.   echo shar: Will not clobber existing file \"'Makefile'\"
  41. else
  42. echo shar: Extracting \"'Makefile'\" \(247 characters\)
  43. sed "s/^X//" >'Makefile' <<'END_OF_FILE'
  44. all:
  45. X    cd perms; $(MAKE)
  46. X    cd permtest; $(MAKE)
  47. X    cd login; $(MAKE)
  48. X    cd in.rshd; $(MAKE)
  49. X    cd in.ftpd; $(MAKE)
  50. X
  51. clean:
  52. X    cd perms; $(MAKE) clean
  53. X    cd permtest; $(MAKE) clean
  54. X    cd login; $(MAKE) clean
  55. X    cd in.rshd; $(MAKE) clean
  56. X    cd in.ftpd; $(MAKE) clean
  57. END_OF_FILE
  58. if test 247 -ne `wc -c <'Makefile'`; then
  59.     echo shar: \"'Makefile'\" unpacked with wrong size!
  60. fi
  61. # end of 'Makefile'
  62. fi
  63. if test -f 'README' -a "${1}" != "-c" ; then 
  64.   echo shar: Will not clobber existing file \"'README'\"
  65. else
  66. echo shar: Extracting \"'README'\" \(2484 characters\)
  67. sed "s/^X//" >'README' <<'END_OF_FILE'
  68. DESCRIPTION:
  69. In a basic BSD environemt only three utilities let people onto a machine:
  70. X    login, rshd, and ftpd.
  71. These three programs are modified to check a YP map called 'permissions'
  72. which determines whether a person is allowed to login.
  73. Control over login is given based on four parameters: hostname, ttyname,
  74. login, and groups.
  75. X
  76. The permissions library routines have been tested on suns, iris, and mips
  77. boxes. The problem is not so much that permissions might be nonportable,
  78. but rather that source for login is unavailable on the other machines I
  79. have access to. Writing a workalike login for a system V box is nontrivial.
  80. permtest, rshd and ftpd have been tested to work though, with minor hacks.
  81. On a BSD-like box, permissions should be trivial to install.
  82. X
  83. Perhaps someone who has written a free system V login could send it to
  84. me. I'd love to support more architectures/operating systems.
  85. X
  86. The permissions library can be used for other purposes too. We also use it
  87. for printer access. Someone suggested doing device access like dialin/dailout
  88. and tape drives through it.
  89. X
  90. INSTALLATION:
  91. X1. Building permissions:
  92. X    # make
  93. X2. Build a permissions map for your network and install it into YP.
  94. X   See your systems manuals for the correct way to install a YP map
  95. X   in your system. Here's what we use in /var/yp/Makefile,
  96. X
  97. permissions.time: $(DIR)/permissions
  98. X    @(sed -e "/^#/d" -e s/#.*$$// $(DIR)/permissions $(CHKPIPE)) | \
  99. X    $(MAKEDBM) - $(YPDBDIR)/$(DOM)/permissions; 
  100. X    @touch permissions.time; 
  101. X    @echo "updated permissions"; 
  102. X    @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOM) permissions; fi
  103. X    @if [ ! $(NOPUSH) ]; then echo "pushed permissions"; fi
  104. X
  105. X   To install the map, on sunos4.1, I would use the following:
  106. X    # touch /etc/permissions
  107. X    # ypmake NOPUSH=1 permissions
  108. X    # foreach i ( `ypcat ypservers` )
  109. X    > rsh $i /usr/etc/yp/ypxfr -h `hostname` permissions
  110. X    > end
  111. X    #
  112. X
  113. X5. Test the permissions database with permtest. For example,
  114. X    # permtest -v deraadt ttyh0 fsa
  115. X    8 groups: staff wheel daemon kmem bin oldstaff telnet cdrom
  116. X    user deraadt permitted on fsa:ttyh0
  117. X
  118. X4. Now install the three remaining parts.
  119. X    login/login -> /bin/login
  120. X    in.ftpd/in.ftpd -> /usr/etc/in.ftpd
  121. X    in.rshd/in.rshd -> /usr/etc/in.rshd
  122. X   Be sure to save copies of your old utilities.
  123. X   Remember, on most systems, login is setuid root.
  124. X
  125. One request. Please clear all changes to this through me. I would be very
  126. unhappy to see five different incompatible versions of this in use.
  127. X
  128. XEnjoy.
  129. deraadt@cpsc.ucalgary.ca
  130. END_OF_FILE
  131. if test 2484 -ne `wc -c <'README'`; then
  132.     echo shar: \"'README'\" unpacked with wrong size!
  133. fi
  134. # end of 'README'
  135. fi
  136. if test ! -d 'examples' ; then
  137.     echo shar: Creating directory \"'examples'\"
  138.     mkdir 'examples'
  139. fi
  140. if test -f 'examples/cpsc.ucalgary.ca' -a "${1}" != "-c" ; then 
  141.   echo shar: Will not clobber existing file \"'examples/cpsc.ucalgary.ca'\"
  142. else
  143. echo shar: Extracting \"'examples/cpsc.ucalgary.ca'\" \(4493 characters\)
  144. sed "s/^X//" >'examples/cpsc.ucalgary.ca' <<'END_OF_FILE'
  145. X# ----------------------------------------------------------------------
  146. X# NIS map = permissions
  147. X# groked by: login, in.rshd, permtest, in.ftpd
  148. X# rsh and ftp generate tty field values of 'rsh' and 'ftp'
  149. X#
  150. X# SYNTAX:
  151. X# entry        : hostname '\t' permlist
  152. X# permlist    : permission `|` permlist
  153. X#        | permission
  154. X#        | null
  155. X# permission    : ttylist ':' authlist
  156. X#        | '$' entry        -> #include an entry
  157. X# ttylist    : tty ',' ttylist
  158. X#        | tty            -> tty regexp
  159. X#        | null
  160. X# authlist    : auth ',' authlist
  161. X#        | auth
  162. X# auth        : + spec        -> add
  163. X#        : - spec        -> delete
  164. X#         | null
  165. X# spec        : user            -> username to change
  166. X#        | '.' group        -> group regexp to change
  167. X#
  168. X# NOTES:
  169. X# Watch how we deny anonomous ftp on every machine with the $admin
  170. X# macro, then allow it on fsa again. fsa is our admin only machine, and
  171. X# does not actually run the ftpd included, but rather a logging ftpd.
  172. X# 
  173. X# Two example users will explain the groups
  174. X# aycock is in groups: c510/L01, c461/L01, and c401/L01. (His account is
  175. X#    actually in /home/c510/L01/aycock)
  176. X# deraadt is in groups: staff wheel daemonkmem bin telnet cdrom
  177. X# 
  178. X# The macros at the top are very important. They groups machines into sets
  179. X# making their management easier.
  180. X# 
  181. X# In some places you will see references to tty's. These are our fast modem
  182. X# racks. We restrict certain groups to using them. Others can go through the
  183. X# slower campus terminal servers.
  184. X# ----------------------------------------------------------------------
  185. X
  186. X# macros
  187. admin        *:+.utils,+.staff,+.wheel,+operator | ftp:-ftp
  188. grad_ws        $admin | *:+.grads,+.profs,+.research,+.summer,+.gl,+.vlsi,+.srdg,+.c502/L01,+.c599/L01,+.c651/L01
  189. prof_ws        $admin | *:+.profs,+.research,+.srdg,+.offstaff
  190. vlsi_ws        $admin | *:+.vlsi,+graham,+olthof,+jevans,+milligan
  191. off_ws        $admin | *:+.offstaff,+.profs
  192. ug_ws        $admin | $grad_ws | *:+.c[456]*
  193. X
  194. X# admin machines
  195. fsa        $admin | ttyb,ttyh?:-.*,+.staff,+.uucp | *:+frangos,+elsie | ftp:+ftp
  196. aa        $admin
  197. rat        $admin | *:+aycock
  198. sev        $admin
  199. atlas        $admin | *:+test,-jamesm
  200. dudes        $admin
  201. glags        $admin
  202. X
  203. X# profs machines
  204. fsc        $admin | *:+.grads,+.profs,+.research,+.srdg,+.vlsi,+.offstaff,+.c491/L01,+.banff,+.visitors | ttyj[0-6]:-.*,+.staff,+.profs,+.offstaff,+gl
  205. interval    $prof_ws
  206. ca        $prof_ws
  207. cb        $prof_ws
  208. cc        $prof_ws | *:+.gl
  209. cd        $prof_ws | *:+.grads,+.research,+.srdg,+.vlsi,+joan
  210. ce        $prof_ws
  211. cf        $prof_ws
  212. cg        $prof_ws
  213. ch        $prof_ws
  214. ic        $prof_ws
  215. golf        $prof_ws
  216. albert        $prof_ws
  217. X
  218. X# grads machines
  219. fsd        $admin | *:+.grads,+.profs,+.research,+.summer,+.vlsi,+gl,+.srdg,+.c502/L01,+.c599/L01,+.banff,+.arc,+conway | ttyh[0-6]:-.*,+.staff,+.profs,+.grads,+.vlsi,+.offstaff,+.research
  220. ab        $grad_ws | *:+publisher
  221. da        $grad_ws
  222. db        $grad_ws
  223. dc        $grad_ws | *:+joan
  224. dd        $grad_ws
  225. de        $grad_ws
  226. df        $grad_ws
  227. dg        $grad_ws
  228. dh        $grad_ws
  229. di        $grad_ws
  230. dj        $grad_ws
  231. dk        $grad_ws
  232. ij        $grad_ws
  233. X
  234. X# vlsi machines
  235. fsg        $vlsi_ws
  236. ga        $vlsi_ws
  237. gb        $vlsi_ws
  238. gc        $vlsi_ws
  239. gd        $vlsi_ws
  240. ge        $vlsi_ws
  241. gf        $vlsi_ws
  242. gg        $vlsi_ws
  243. gh        $vlsi_ws
  244. X
  245. X# office staff machines
  246. ia        $off_ws
  247. ih        $off_ws
  248. X
  249. X# undergraduate workstations
  250. ea        $ug_ws
  251. eb        $ug_ws
  252. ec        $ug_ws
  253. ed        $ug_ws
  254. ee        $ug_ws
  255. ef        $ug_ws
  256. eg        $ug_ws
  257. eh        $ug_ws
  258. ei        $ug_ws
  259. ej        $ug_ws
  260. ha        $ug_ws
  261. hb        $ug_ws
  262. hc        $ug_ws
  263. hd        $ug_ws
  264. he        $ug_ws
  265. hf        $ug_ws
  266. hg        $ug_ws
  267. hh        $ug_ws
  268. hi        $ug_ws
  269. ib        $ug_ws
  270. id        $ug_ws
  271. ie        $ug_ws
  272. if        $ug_ws
  273. X
  274. X# graphicsland fileserver
  275. gfx        $admin | *:+.gl,+thorne
  276. X
  277. X# myths. these machines do not run the right login yet.
  278. bfly        $grad_ws
  279. irisa        $admin | *:+.gl,+.c55[13]*
  280. irisb        $admin | *:+.gl,+.c55[13]*
  281. irisc        $admin | *:+.gl
  282. irisd        $admin | *:+.gl
  283. irise        $admin | *:+.gl
  284. irisf        $admin | *:+.gl,+.c55[13]*
  285. X
  286. X# remaining machines. Anyone may use an undergrad machine.
  287. X# be careful - the $admin is at the end to turn off anon ftp
  288. X*        *:+.*,-.uucp | $admin
  289. X
  290. X# PRINTERS
  291. X# Our printer permissions are done through permissions as well. Sorry,
  292. X# this distribution of permissions does not include our lpr hacks.
  293. X# I left this in here simply as an example.
  294. X
  295. lp1        *:+.*,-.nlp
  296. lp2        *:+.*,-.nlp
  297. X
  298. cs1        $admin | *:+.grads,+.research,+.profs,+.offstaff,+.srdg,+.submit | *:+.cs1,-.ncs1
  299. cs2        $admin | *:+.grads,+.research,+.profs,+.offstaff,+.srdg,+.vlsi | *:+.cs2,-.ncs2
  300. X
  301. alw1        $admin | *:+.profs,+.offstaff,+.grads | *:+.alw1,-.nalw1
  302. alw2        $admin | *:+.profs,+.offstaff,+.vlsi | *:+.alw2,-.nalw2
  303. alw3        $admin | *:+.grads,+.research,+.profs,+.srdg,+.vlsi | *:+.alw3,-.nalw3
  304. alw4        $admin | *:+.grads,+.research,+.profs,+.offstaff,+.srdg,+.vlsi | *:+.alw4,-.nalw4
  305. X
  306. bp        $admin | *:+.bp,-.nbp
  307. ip        $admin | *:+.grads,+.research,+.profs,+.srdg,+.c481* | *:+.ip,-.nip
  308. END_OF_FILE
  309. if test 4493 -ne `wc -c <'examples/cpsc.ucalgary.ca'`; then
  310.     echo shar: \"'examples/cpsc.ucalgary.ca'\" unpacked with wrong size!
  311. fi
  312. # end of 'examples/cpsc.ucalgary.ca'
  313. fi
  314. if test ! -d 'in.ftpd' ; then
  315.     echo shar: Creating directory \"'in.ftpd'\"
  316.     mkdir 'in.ftpd'
  317. fi
  318. if test -f 'in.ftpd/Makefile' -a "${1}" != "-c" ; then 
  319.   echo shar: Will not clobber existing file \"'in.ftpd/Makefile'\"
  320. else
  321. echo shar: Extracting \"'in.ftpd/Makefile'\" \(203 characters\)
  322. sed "s/^X//" >'in.ftpd/Makefile' <<'END_OF_FILE'
  323. OBJ = ftpd.o ftpcmd.o glob.o popen.o logwtmp.o vers.o\
  324. X    ../perms/perms.o ../perms/glob_match.o
  325. CFLAGS = -g -DPERMS
  326. X
  327. in.ftpd: $(OBJ)
  328. X    $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJ)
  329. X
  330. clean:
  331. X    $(RM) *.o *~ in.ftpd
  332. END_OF_FILE
  333. if test 203 -ne `wc -c <'in.ftpd/Makefile'`; then
  334.     echo shar: \"'in.ftpd/Makefile'\" unpacked with wrong size!
  335. fi
  336. # end of 'in.ftpd/Makefile'
  337. fi
  338. if test -f 'in.ftpd/logwtmp.c' -a "${1}" != "-c" ; then 
  339.   echo shar: Will not clobber existing file \"'in.ftpd/logwtmp.c'\"
  340. else
  341. echo shar: Extracting \"'in.ftpd/logwtmp.c'\" \(1604 characters\)
  342. sed "s/^X//" >'in.ftpd/logwtmp.c' <<'END_OF_FILE'
  343. X/*
  344. X * Copyright (c) 1988 The Regents of the University of California.
  345. X * All rights reserved.
  346. X *
  347. X * Redistribution and use in source and binary forms are permitted
  348. X * provided that the above copyright notice and this paragraph are
  349. X * duplicated in all such forms and that any documentation,
  350. X * advertising materials, and other materials related to such
  351. X * distribution and use acknowledge that the software was developed
  352. X * by the University of California, Berkeley.  The name of the
  353. X * University may not be used to endorse or promote products derived
  354. X * from this software without specific prior written permission.
  355. X */
  356. X
  357. X#ifndef lint
  358. static char sccsid[] = "@(#)logwtmp.c 1.1 90/03/23 SMI"; /* from UCB 5.3 12/7/88 */
  359. X#endif /* not lint */
  360. X
  361. X#include <sys/types.h>
  362. X#include <sys/file.h>
  363. X#include <sys/time.h>
  364. X#include <sys/stat.h>
  365. X#include <utmp.h>
  366. X
  367. X#define    WTMPFILE    "/var/adm/wtmp"
  368. X
  369. static int fd = -1;
  370. X
  371. X/*
  372. X * Modified version of logwtmp that holds wtmp file open
  373. X * after first call, for use with ftp (which may chroot
  374. X * after login, but before logout).
  375. X */
  376. logwtmp(line, name, host)
  377. X    char *line, *name, *host;
  378. X{
  379. X    struct utmp ut;
  380. X    struct stat buf;
  381. X    time_t time();
  382. X    char *strncpy();
  383. X
  384. X    if (fd < 0 && (fd = open(WTMPFILE, O_WRONLY|O_APPEND, 0)) < 0)
  385. X        return;
  386. X    if (fstat(fd, &buf) == 0) {
  387. X        (void)strncpy(ut.ut_line, line, sizeof(ut.ut_line));
  388. X        (void)strncpy(ut.ut_name, name, sizeof(ut.ut_name));
  389. X        (void)strncpy(ut.ut_host, host, sizeof(ut.ut_host));
  390. X        (void)time(&ut.ut_time);
  391. X        if (write(fd, (char *)&ut, sizeof(struct utmp)) !=
  392. X            sizeof(struct utmp))
  393. X            (void)ftruncate(fd, buf.st_size);
  394. X    }
  395. X}
  396. END_OF_FILE
  397. if test 1604 -ne `wc -c <'in.ftpd/logwtmp.c'`; then
  398.     echo shar: \"'in.ftpd/logwtmp.c'\" unpacked with wrong size!
  399. fi
  400. # end of 'in.ftpd/logwtmp.c'
  401. fi
  402. if test -f 'in.ftpd/popen.c' -a "${1}" != "-c" ; then 
  403.   echo shar: Will not clobber existing file \"'in.ftpd/popen.c'\"
  404. else
  405. echo shar: Extracting \"'in.ftpd/popen.c'\" \(3504 characters\)
  406. sed "s/^X//" >'in.ftpd/popen.c' <<'END_OF_FILE'
  407. X/*
  408. X * Copyright (c) 1988 The Regents of the University of California.
  409. X * All rights reserved.
  410. X *
  411. X * This code is derived from software written by Ken Arnold and
  412. X * published in UNIX Review, Vol. 6, No. 8.
  413. X *
  414. X * Redistribution and use in source and binary forms are permitted
  415. X * provided that the above copyright notice and this paragraph are
  416. X * duplicated in all such forms and that any documentation,
  417. X * advertising materials, and other materials related to such
  418. X * distribution and use acknowledge that the software was developed
  419. X * by the University of California, Berkeley.  The name of the
  420. X * University may not be used to endorse or promote products derived
  421. X * from this software without specific prior written permission.
  422. X */
  423. X
  424. X#ifndef lint
  425. static char sccsid[] = "@(#)popen.c 1.1 90/03/23 SMI"; /* from UCB 5.4 12/7/88 */
  426. X#endif /* not lint */
  427. X
  428. X#include <sys/types.h>
  429. X#include <sys/signal.h>
  430. X#include <sys/wait.h>
  431. X#include <stdio.h>
  432. X
  433. X/*
  434. X * Special version of popen which avoids call to shell.  This insures noone
  435. X * may create a pipe to a hidden program as a side effect of a list or dir
  436. X * command.
  437. X */
  438. static int *pids;
  439. static int fds;
  440. X
  441. XFILE *
  442. ftpd_popen(program, type)
  443. X    char *program, *type;
  444. X{
  445. X    register char *cp;
  446. X    FILE *iop;
  447. X    int argc, gargc, pdes[2], pid;
  448. X    char **pop, *argv[100], *gargv[1000], *vv[2];
  449. X    extern char **glob(), **copyblk(), *strtok(), *malloc();
  450. X
  451. X    if (*type != 'r' && *type != 'w' || type[1])
  452. X        return(NULL);
  453. X
  454. X    if (!pids) {
  455. X        if ((fds = getdtablesize()) <= 0)
  456. X            return(NULL);
  457. X        if ((pids = (int *)malloc((u_int)(fds * sizeof(int)))) == NULL)
  458. X            return(NULL);
  459. X        bzero((char *)pids, fds * sizeof(int));
  460. X    }
  461. X    if (pipe(pdes) < 0)
  462. X        return(NULL);
  463. X
  464. X    /* break up string into pieces */
  465. X    for (argc = 0, cp = program;; cp = NULL)
  466. X        if (!(argv[argc++] = strtok(cp, " \t\n")))
  467. X            break;
  468. X
  469. X    /* glob each piece */
  470. X    gargv[0] = argv[0];
  471. X    for (gargc = argc = 1; argv[argc]; argc++) {
  472. X        if (!(pop = glob(argv[argc]))) {    /* globbing failed */
  473. X            vv[0] = argv[argc];
  474. X            vv[1] = NULL;
  475. X            pop = copyblk(vv);
  476. X        }
  477. X        argv[argc] = (char *)pop;        /* save to free later */
  478. X        while (*pop && gargc < 1000)
  479. X            gargv[gargc++] = *pop++;
  480. X    }
  481. X    gargv[gargc] = NULL;
  482. X
  483. X    iop = NULL;
  484. X    switch(pid = vfork()) {
  485. X    case -1:            /* error */
  486. X        (void)close(pdes[0]);
  487. X        (void)close(pdes[1]);
  488. X        goto free;
  489. X        /* NOTREACHED */
  490. X    case 0:                /* child */
  491. X        if (*type == 'r') {
  492. X            if (pdes[1] != 1) {
  493. X            /*
  494. X             * Need to grab stderr too for new ls
  495. X             */
  496. X                dup2(pdes[1], 2);
  497. X                dup2(pdes[1], 1);
  498. X                (void)close(pdes[1]);
  499. X            }
  500. X            (void)close(pdes[0]);
  501. X        } else {
  502. X            if (pdes[0] != 0) {
  503. X                dup2(pdes[0], 0);
  504. X                (void)close(pdes[0]);
  505. X            }
  506. X            (void)close(pdes[1]);
  507. X        }
  508. X        execv(gargv[0], gargv);
  509. X        _exit(1);
  510. X    }
  511. X    /* parent; assume fdopen can't fail...  */
  512. X    if (*type == 'r') {
  513. X        iop = fdopen(pdes[0], type);
  514. X        (void)close(pdes[1]);
  515. X    } else {
  516. X        iop = fdopen(pdes[1], type);
  517. X        (void)close(pdes[0]);
  518. X    }
  519. X    pids[fileno(iop)] = pid;
  520. X
  521. free:    for (argc = 1; argv[argc] != NULL; argc++)
  522. X        blkfree((char **)argv[argc]);
  523. X    return(iop);
  524. X}
  525. X
  526. ftpd_pclose(iop)
  527. X    FILE *iop;
  528. X{
  529. X    register int fdes;
  530. X    int omask;
  531. X    union wait stat_loc;
  532. X    int pid;
  533. X
  534. X    /*
  535. X     * pclose returns -1 if stream is not associated with a
  536. X     * `popened' command, or, if already `pclosed'.
  537. X     */
  538. X    if (pids == 0 || pids[fdes = fileno(iop)] == 0)
  539. X        return(-1);
  540. X    (void)fclose(iop);
  541. X    omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
  542. X    while ((pid = wait(&stat_loc)) != pids[fdes] && pid != -1);
  543. X    (void)sigsetmask(omask);
  544. X    pids[fdes] = 0;
  545. X    return(pid == -1 ? -1 : stat_loc.w_status);
  546. X}
  547. END_OF_FILE
  548. if test 3504 -ne `wc -c <'in.ftpd/popen.c'`; then
  549.     echo shar: \"'in.ftpd/popen.c'\" unpacked with wrong size!
  550. fi
  551. # end of 'in.ftpd/popen.c'
  552. fi
  553. if test -f 'in.ftpd/vers.c' -a "${1}" != "-c" ; then 
  554.   echo shar: Will not clobber existing file \"'in.ftpd/vers.c'\"
  555. else
  556. echo shar: Extracting \"'in.ftpd/vers.c'\" \(64 characters\)
  557. sed "s/^X//" >'in.ftpd/vers.c' <<'END_OF_FILE'
  558. X/*    @(#)vers.c 1.1 90/03/23 SMI    */
  559. char version[] = "SunOS 4.1";
  560. END_OF_FILE
  561. if test 64 -ne `wc -c <'in.ftpd/vers.c'`; then
  562.     echo shar: \"'in.ftpd/vers.c'\" unpacked with wrong size!
  563. fi
  564. # end of 'in.ftpd/vers.c'
  565. fi
  566. if test ! -d 'in.rshd' ; then
  567.     echo shar: Creating directory \"'in.rshd'\"
  568.     mkdir 'in.rshd'
  569. fi
  570. if test -f 'in.rshd/Makefile' -a "${1}" != "-c" ; then 
  571.   echo shar: Will not clobber existing file \"'in.rshd/Makefile'\"
  572. else
  573. echo shar: Extracting \"'in.rshd/Makefile'\" \(160 characters\)
  574. sed "s/^X//" >'in.rshd/Makefile' <<'END_OF_FILE'
  575. OBJ = in.rshd.o ../perms/perms.o ../perms/glob_match.o
  576. CFLAGS = -g -DPERMS
  577. X
  578. in.rshd:    $(OBJ)
  579. X        $(CC) $(LDFLAGS) $(OBJ) -o in.rshd
  580. X
  581. clean:
  582. X        $(RM) *~ *.o in.rshd
  583. END_OF_FILE
  584. if test 160 -ne `wc -c <'in.rshd/Makefile'`; then
  585.     echo shar: \"'in.rshd/Makefile'\" unpacked with wrong size!
  586. fi
  587. # end of 'in.rshd/Makefile'
  588. fi
  589. if test -f 'in.rshd/in.rshd.c' -a "${1}" != "-c" ; then 
  590.   echo shar: Will not clobber existing file \"'in.rshd/in.rshd.c'\"
  591. else
  592. echo shar: Extracting \"'in.rshd/in.rshd.c'\" \(6522 characters\)
  593. sed "s/^X//" >'in.rshd/in.rshd.c' <<'END_OF_FILE'
  594. X/*
  595. X * Copyright (c) 1983 Regents of the University of California.
  596. X * All rights reserved.  The Berkeley software License Agreement
  597. X * specifies the terms and conditions for redistribution.
  598. X */
  599. X
  600. X#ifndef lint
  601. char copyright[] =
  602. X"@(#) Copyright (c) 1983 Regents of the University of California.\n\
  603. X All rights reserved.\n";
  604. X#endif not lint
  605. X
  606. X#ifndef lint
  607. static char sccsid[] = "@(#)rshd.c    5.7 (Berkeley) 5/9/86";
  608. X#endif not lint
  609. X
  610. X/*
  611. X * remote shell server:
  612. X *    remuser\0
  613. X *    locuser\0
  614. X *    command\0
  615. X *    data
  616. X */
  617. X#include <sys/ioctl.h>
  618. X#include <sys/param.h>
  619. X#include <sys/socket.h>
  620. X#include <sys/time.h>
  621. X
  622. X#include <netinet/in.h>
  623. X
  624. X#include <arpa/inet.h>
  625. X
  626. X#include <stdio.h>
  627. X#include <errno.h>
  628. X#include <pwd.h>
  629. X#include <signal.h>
  630. X#include <netdb.h>
  631. X#include <syslog.h>
  632. X
  633. X
  634. X#ifdef PERMS
  635. X#include <grp.h>
  636. char *strdup(), *grpnames[NGROUPS+1];
  637. int ngrps, lp;
  638. struct group *grp;
  639. extern int permcheck();
  640. X#endif
  641. X
  642. int    errno;
  643. char    *index(), *rindex(), *strncat();
  644. X/*VARARGS1*/
  645. int    error();
  646. X
  647. X/*ARGSUSED*/
  648. main(argc, argv)
  649. X    int argc;
  650. X    char **argv;
  651. X{
  652. X    struct linger linger;
  653. X    int on = 1, fromlen;
  654. X    struct sockaddr_in from;
  655. X
  656. X    openlog("rsh", LOG_PID | LOG_ODELAY, LOG_DAEMON);
  657. X    fromlen = sizeof (from);
  658. X    if (getpeername(0, &from, &fromlen) < 0) {
  659. X        fprintf(stderr, "%s: ", argv[0]);
  660. X        perror("getpeername");
  661. X        _exit(1);
  662. X    }
  663. X    if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, (char *)&on,
  664. X        sizeof (on)) < 0)
  665. X        syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
  666. X    linger.l_onoff = 1;
  667. X    linger.l_linger = 60;            /* XXX */
  668. X    if (setsockopt(0, SOL_SOCKET, SO_LINGER, (char *)&linger,
  669. X        sizeof (linger)) < 0)
  670. X        syslog(LOG_WARNING, "setsockopt (SO_LINGER): %m");
  671. X    doit(dup(0), &from);
  672. X}
  673. X
  674. char    username[20] = "USER=";
  675. char    homedir[64] = "HOME=";
  676. char    shell[64] = "SHELL=";
  677. char    *envinit[] =
  678. X        {homedir, shell, "PATH=:/usr/ucb:/bin:/usr/bin", username, 0};
  679. char    **environ;
  680. X
  681. doit(f, fromp)
  682. X    int f;
  683. X    struct sockaddr_in *fromp;
  684. X{
  685. X    char cmdbuf[NCARGS+1], *cp;
  686. X    char locuser[16], remuser[16];
  687. X    struct passwd *pwd;
  688. X    int s;
  689. X    struct hostent *hp;
  690. X    char *hostname;
  691. X    short port;
  692. X    int pv[2], pid, ready, readfrom, cc;
  693. X    char buf[BUFSIZ], sig;
  694. X    int one = 1;
  695. X
  696. X    (void) signal(SIGINT, SIG_DFL);
  697. X    (void) signal(SIGQUIT, SIG_DFL);
  698. X    (void) signal(SIGTERM, SIG_DFL);
  699. X#ifdef DEBUG
  700. X    { int t = open("/dev/tty", 2);
  701. X      if (t >= 0) {
  702. X        ioctl(t, TIOCNOTTY, (char *)0);
  703. X        (void) close(t);
  704. X      }
  705. X    }
  706. X#endif
  707. X    fromp->sin_port = ntohs((u_short)fromp->sin_port);
  708. X    if (fromp->sin_family != AF_INET ||
  709. X        fromp->sin_port >= IPPORT_RESERVED) {
  710. X        syslog(LOG_ERR, "malformed from address\n");
  711. X        exit(1);
  712. X    }
  713. X    (void) alarm(60);
  714. X    port = 0;
  715. X    for (;;) {
  716. X        char c;
  717. X        if (read(f, &c, 1) != 1) {
  718. X            syslog(LOG_ERR, "read: %m");
  719. X            shutdown(f, 1+1);
  720. X            exit(1);
  721. X        }
  722. X        if (c == 0)
  723. X            break;
  724. X        port = port * 10 + c - '0';
  725. X    }
  726. X    (void) alarm(0);
  727. X    if (port != 0) {
  728. X        int lport = IPPORT_RESERVED - 1;
  729. X        s = rresvport(&lport);
  730. X        if (s < 0) {
  731. X            syslog(LOG_ERR, "can't get stderr port: %m");
  732. X            exit(1);
  733. X        }
  734. X        if (port >= IPPORT_RESERVED) {
  735. X            syslog(LOG_ERR, "2nd port not reserved\n");
  736. X            exit(1);
  737. X        }
  738. X        fromp->sin_port = htons((u_short)port);
  739. X        if (connect(s, fromp, sizeof (*fromp)) < 0) {
  740. X            syslog(LOG_INFO, "connect second port: %m");
  741. X            exit(1);
  742. X        }
  743. X    }
  744. X    dup2(f, 0);
  745. X    dup2(f, 1);
  746. X    dup2(f, 2);
  747. X    hp = gethostbyaddr((char *)&fromp->sin_addr, sizeof (struct in_addr),
  748. X        fromp->sin_family);
  749. X    if (hp)
  750. X        hostname = hp->h_name;
  751. X    else
  752. X        hostname = inet_ntoa(fromp->sin_addr);
  753. X    getstr(remuser, sizeof(remuser), "remuser");
  754. X    getstr(locuser, sizeof(locuser), "locuser");
  755. X    getstr(cmdbuf, sizeof(cmdbuf), "command");
  756. X    setpwent();
  757. X    pwd = getpwnam(locuser);
  758. X    if (pwd == NULL) {
  759. X        error("Login incorrect.\n");
  760. X        exit(1);
  761. X    }
  762. X    endpwent();
  763. X    if (chdir(pwd->pw_dir) < 0) {
  764. X        (void) chdir("/");
  765. X#ifdef notdef
  766. X        error("No remote directory.\n");
  767. X        exit(1);
  768. X#endif
  769. X    }
  770. X    if (pwd->pw_passwd != 0 && *pwd->pw_passwd != '\0' &&
  771. X        ruserok(hostname, pwd->pw_uid == 0, remuser, locuser) < 0) {
  772. X        error("Permission denied.\n");
  773. X        exit(1);
  774. X    }
  775. X
  776. X#ifdef PERMS
  777. X    /* build groups so we can look them up in 'permissions'
  778. X     * this check is not run for uid 0
  779. X     */
  780. X    if(pwd->pw_uid != 0) {
  781. X        setgrent();
  782. X        ngrps = 0;
  783. X        grp=getgrgid(pwd->pw_gid);
  784. X        grpnames[ngrps++] = strdup(grp->gr_name);
  785. X        while( grp=getgrent() ) {
  786. X            if(pwd->pw_gid == grp->gr_gid)
  787. X                continue;
  788. X            while(*grp->gr_mem) {
  789. X                if( !strcmp(locuser, *grp->gr_mem)) {
  790. X                    grpnames[ngrps++] = strdup(grp->gr_name);
  791. X                }
  792. X                grp->gr_mem++;
  793. X            }
  794. X        }
  795. X        endgrent();
  796. X        grpnames[ngrps] = NULL;
  797. X
  798. X        lp = permcheck(locuser, "rsh", grpnames, NULL);
  799. X        if(!lp) {
  800. X            syslog(LOG_CRIT,
  801. X                "rsh:%s not permitted", locuser);
  802. X            error("Permission denied.\n");
  803. X            exit(1);
  804. X        }        
  805. X    }
  806. X#endif
  807. X
  808. X    (void) write(2, "\0", 1);
  809. X    if (port) {
  810. X        if (pipe(pv) < 0) {
  811. X            error("Can't make pipe.\n");
  812. X            exit(1);
  813. X        }
  814. X        pid = fork();
  815. X        if (pid == -1)  {
  816. X            error("Try again.\n");
  817. X            exit(1);
  818. X        }
  819. X        if (pid) {
  820. X            (void) close(0); (void) close(1); (void) close(2);
  821. X            (void) close(f); (void) close(pv[1]);
  822. X            readfrom = (1<<s) | (1<<pv[0]);
  823. X            ioctl(pv[0], FIONBIO, (char *)&one);
  824. X            /* should set s nbio! */
  825. X            do {
  826. X                ready = readfrom;
  827. X                if (select(16, &ready, (fd_set *)0,
  828. X                    (fd_set *)0, (struct timeval *)0) < 0)
  829. X                    break;
  830. X                if (ready & (1<<s)) {
  831. X                    if (read(s, &sig, 1) <= 0)
  832. X                        readfrom &= ~(1<<s);
  833. X                    else
  834. X                        killpg(pid, sig);
  835. X                }
  836. X                if (ready & (1<<pv[0])) {
  837. X                    errno = 0;
  838. X                    cc = read(pv[0], buf, sizeof (buf));
  839. X                    if (cc <= 0) {
  840. X                        shutdown(s, 1+1);
  841. X                        readfrom &= ~(1<<pv[0]);
  842. X                    } else
  843. X                        (void) write(s, buf, cc);
  844. X                }
  845. X            } while (readfrom);
  846. X            exit(0);
  847. X        }
  848. X        setpgrp(0, getpid());
  849. X        (void) close(s); (void) close(pv[0]);
  850. X        dup2(pv[1], 2);
  851. X    }
  852. X    if (*pwd->pw_shell == '\0')
  853. X        pwd->pw_shell = "/bin/sh";
  854. X    (void) close(f);
  855. X    (void) setgid((gid_t)pwd->pw_gid);
  856. X    initgroups(pwd->pw_name, pwd->pw_gid);
  857. X    (void) setuid((uid_t)pwd->pw_uid);
  858. X    environ = envinit;
  859. X    strncat(homedir, pwd->pw_dir, sizeof(homedir)-6);
  860. X    strncat(shell, pwd->pw_shell, sizeof(shell)-7);
  861. X    strncat(username, pwd->pw_name, sizeof(username)-6);
  862. X    cp = rindex(pwd->pw_shell, '/');
  863. X    if (cp)
  864. X        cp++;
  865. X    else
  866. X        cp = pwd->pw_shell;
  867. X    execl(pwd->pw_shell, cp, "-c", cmdbuf, 0);
  868. X    perror(pwd->pw_shell);
  869. X    exit(1);
  870. X}
  871. X
  872. X/*VARARGS1*/
  873. error(fmt, a1, a2, a3)
  874. X    char *fmt;
  875. X    int a1, a2, a3;
  876. X{
  877. X    char buf[BUFSIZ];
  878. X
  879. X    buf[0] = 1;
  880. X    (void) sprintf(buf+1, fmt, a1, a2, a3);
  881. X    (void) write(2, buf, strlen(buf));
  882. X}
  883. X
  884. getstr(buf, cnt, err)
  885. X    char *buf;
  886. X    int cnt;
  887. X    char *err;
  888. X{
  889. X    char c;
  890. X
  891. X    do {
  892. X        if (read(0, &c, 1) != 1)
  893. X            exit(1);
  894. X        *buf++ = c;
  895. X        if (--cnt == 0) {
  896. X            error("%s too long\n", err);
  897. X            exit(1);
  898. X        }
  899. X    } while (c != 0);
  900. X}
  901. END_OF_FILE
  902. if test 6522 -ne `wc -c <'in.rshd/in.rshd.c'`; then
  903.     echo shar: \"'in.rshd/in.rshd.c'\" unpacked with wrong size!
  904. fi
  905. # end of 'in.rshd/in.rshd.c'
  906. fi
  907. if test ! -d 'login' ; then
  908.     echo shar: Creating directory \"'login'\"
  909.     mkdir 'login'
  910. fi
  911. if test -f 'login/Makefile' -a "${1}" != "-c" ; then 
  912.   echo shar: Will not clobber existing file \"'login/Makefile'\"
  913. else
  914. echo shar: Extracting \"'login/Makefile'\" \(164 characters\)
  915. sed "s/^X//" >'login/Makefile' <<'END_OF_FILE'
  916. OBJ = login.o ../perms/perms.o ../perms/glob_match.o
  917. CFLAGS = -g -DPERMS -DMAILPING
  918. X
  919. login:        $(OBJ)
  920. X        $(CC) $(LDFLAGS) $(OBJ) -o login
  921. X
  922. clean:
  923. X        $(RM) *~ *.o login
  924. END_OF_FILE
  925. if test 164 -ne `wc -c <'login/Makefile'`; then
  926.     echo shar: \"'login/Makefile'\" unpacked with wrong size!
  927. fi
  928. # end of 'login/Makefile'
  929. fi
  930. if test ! -d 'perms' ; then
  931.     echo shar: Creating directory \"'perms'\"
  932.     mkdir 'perms'
  933. fi
  934. if test -f 'perms/Makefile' -a "${1}" != "-c" ; then 
  935.   echo shar: Will not clobber existing file \"'perms/Makefile'\"
  936. else
  937. echo shar: Extracting \"'perms/Makefile'\" \(293 characters\)
  938. sed "s/^X//" >'perms/Makefile' <<'END_OF_FILE'
  939. YACCFLAGS = -d
  940. OBJ = perms.o glob_match.o
  941. CFLAGS = -g -DPERMS
  942. X
  943. all:        glob_match.o perms.o
  944. X
  945. perms.o:    perms.y
  946. X        yacc $(YACCFLAGS) perms.y
  947. X        sed -e "s/yy/xx/g" -e "s/YY/XX/g" y.tab.c > x.tab.c
  948. X        $(CC) $(CFLAGS) -c x.tab.c -o perms.o
  949. X        $(RM) y.tab.c x.tab.c
  950. X
  951. clean:
  952. X        $(RM) *~ *.o y.tab.h y.tab.c
  953. END_OF_FILE
  954. if test 293 -ne `wc -c <'perms/Makefile'`; then
  955.     echo shar: \"'perms/Makefile'\" unpacked with wrong size!
  956. fi
  957. # end of 'perms/Makefile'
  958. fi
  959. if test -f 'perms/glob_match.c' -a "${1}" != "-c" ; then 
  960.   echo shar: Will not clobber existing file \"'perms/glob_match.c'\"
  961. else
  962. echo shar: Extracting \"'perms/glob_match.c'\" \(7660 characters\)
  963. sed "s/^X//" >'perms/glob_match.c' <<'END_OF_FILE'
  964. X/* File-name wildcard pattern matching for GNU.
  965. X   Copyright (C) 1985, 1988 Free Software Foundation, Inc.
  966. X
  967. X               NO WARRANTY
  968. X
  969. X  BECAUSE THIS PROGRAM IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY
  970. NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW.  EXCEPT
  971. WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC,
  972. RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE THIS PROGRAM "AS IS"
  973. WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
  974. BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  975. XFITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY
  976. AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE PROGRAM PROVE
  977. DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR
  978. CORRECTION.
  979. X
  980. X IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M.
  981. STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY
  982. WHO MAY MODIFY AND REDISTRIBUTE THIS PROGRAM AS PERMITTED BELOW, BE
  983. LIABLE TO YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR
  984. OTHER SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
  985. USE OR INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR
  986. DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR
  987. A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) THIS
  988. PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
  989. DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY.
  990. X
  991. X        GENERAL PUBLIC LICENSE TO COPY
  992. X
  993. X  1. You may copy and distribute verbatim copies of this source file
  994. as you receive it, in any medium, provided that you conspicuously and
  995. appropriately publish on each copy a valid copyright notice "Copyright
  996. X(C) 1988 Free Software Foundation, Inc."; and include following the
  997. copyright notice a verbatim copy of the above disclaimer of warranty
  998. and of this License.
  999. X
  1000. X  2. You may modify your copy or copies of this source file or
  1001. any portion of it, and copy and distribute such modifications under
  1002. the terms of Paragraph 1 above, provided that you also do the following:
  1003. X
  1004. X    a) cause the modified files to carry prominent notices stating
  1005. X    that you changed the files and the date of any change; and
  1006. X
  1007. X    b) cause the whole of any work that you distribute or publish,
  1008. X    that in whole or in part contains or is a derivative of this
  1009. X    program or any part thereof, to be licensed at no charge to all
  1010. X    third parties on terms identical to those contained in this
  1011. X    License Agreement (except that you may choose to grant more extensive
  1012. X    warranty protection to some or all third parties, at your option).
  1013. X
  1014. X    c) You may charge a distribution fee for the physical act of
  1015. X    transferring a copy, and you may at your option offer warranty
  1016. X    protection in exchange for a fee.
  1017. X
  1018. Mere aggregation of another unrelated program with this program (or its
  1019. derivative) on a volume of a storage or distribution medium does not bring
  1020. the other program under the scope of these terms.
  1021. X
  1022. X  3. You may copy and distribute this program (or a portion or derivative
  1023. of it, under Paragraph 2) in object code or executable form under the terms
  1024. of Paragraphs 1 and 2 above provided that you also do one of the following:
  1025. X
  1026. X    a) accompany it with the complete corresponding machine-readable
  1027. X    source code, which must be distributed under the terms of
  1028. X    Paragraphs 1 and 2 above; or,
  1029. X
  1030. X    b) accompany it with a written offer, valid for at least three
  1031. X    years, to give any third party free (except for a nominal
  1032. X    shipping charge) a complete machine-readable copy of the
  1033. X    corresponding source code, to be distributed under the terms of
  1034. X    Paragraphs 1 and 2 above; or,
  1035. X
  1036. X    c) accompany it with the information you received as to where the
  1037. X    corresponding source code may be obtained.  (This alternative is
  1038. X    allowed only for noncommercial distribution and only if you
  1039. X    received the program in object code or executable form alone.)
  1040. X
  1041. XFor an executable file, complete source code means all the source code for
  1042. all modules it contains; but, as a special exception, it need not include
  1043. source code for modules which are standard libraries that accompany the
  1044. operating system on which the executable file runs.
  1045. X
  1046. X  4. You may not copy, sublicense, distribute or transfer this program
  1047. except as expressly provided under this License Agreement.  Any attempt
  1048. otherwise to copy, sublicense, distribute or transfer this program is void and
  1049. your rights to use the program under this License agreement shall be
  1050. automatically terminated.  However, parties who have received computer
  1051. software programs from you with this License Agreement will not have
  1052. their licenses terminated so long as such parties remain in full compliance.
  1053. X
  1054. X
  1055. In other words, you are welcome to use, share and improve this program.
  1056. You are forbidden to forbid anyone else to use, share and improve
  1057. what you give them.   Help stamp out software-hoarding!  */
  1058. X
  1059. X/* Match the pattern PATTERN against the string TEXT;
  1060. X   return 1 if it matches, 0 otherwise.
  1061. X
  1062. X   A match means the entire string TEXT is used up in matching.
  1063. X
  1064. X   In the pattern string, `*' matches any sequence of characters,
  1065. X   `?' matches any character, [SET] matches any character in the specified set,
  1066. X   [^SET] matches any character not in the specified set.
  1067. X
  1068. X   A set is composed of characters or ranges; a range looks like
  1069. X   character hyphen character (as in 0-9 or A-Z).
  1070. X   [0-9a-zA-Z_] is the set of characters allowed in C identifiers.
  1071. X   Any other character in the pattern must be matched exactly.
  1072. X
  1073. X   To suppress the special syntactic significance of any of `[]*?^-\',
  1074. X   and match the character exactly, precede it with a `\'.
  1075. X
  1076. X   If DOT_SPECIAL is nonzero,
  1077. X   `*' and `?' do not match `.' at the beginning of TEXT.  */
  1078. X
  1079. int
  1080. glob_match (pattern, text, dot_special)
  1081. X     char *pattern, *text;
  1082. X     int dot_special;
  1083. X{
  1084. X  register char *p = pattern, *t = text;
  1085. X  register char c;
  1086. X
  1087. X  while ((c = *p++))
  1088. X    {
  1089. X      switch (c)
  1090. X    {
  1091. X    case '?':
  1092. X      if (*t == 0 || (dot_special && t == text && *t == '.')) return 0;
  1093. X      else ++t;
  1094. X      break;
  1095. X
  1096. X    case '\\':
  1097. X      if (*p++ != *t++) return 0;
  1098. X      break;
  1099. X
  1100. X    case '*':
  1101. X      if (dot_special && t == text && *t == '.')
  1102. X        return 0;
  1103. X      return star_glob_match (p, t);
  1104. X
  1105. X    case '[':
  1106. X      {
  1107. X        register char c1 = *t++;
  1108. X        register int invert = (*p == '^');
  1109. X
  1110. X        if (invert) p++;
  1111. X
  1112. X        c = *p++;
  1113. X        while (1)
  1114. X          {
  1115. X        register char cstart = c, cend = c;
  1116. X
  1117. X        if (c == '\\')
  1118. X          {
  1119. X            cstart = *p++; cend = cstart;
  1120. X          }
  1121. X        c = *p++;
  1122. X        if (c == '-')
  1123. X          { cend = *p++; if (cend == '\\') cend = *p++; c = *p++; }
  1124. X        if (c1 >= cstart && c1 <= cend) goto match;
  1125. X        if (c == ']')
  1126. X          break;
  1127. X          }
  1128. X        if (!invert) return 0;
  1129. X        break;
  1130. X
  1131. X      match:
  1132. X        /* Skip the rest of the [...] construct that already matched.  */
  1133. X        while (c != ']')
  1134. X          {
  1135. X            c = *p++;
  1136. X        if (c == '\\') p++;
  1137. X          }
  1138. X        if (invert) return 0;
  1139. X        break;
  1140. X      }
  1141. X
  1142. X    default:
  1143. X      if (c != *t++) return 0;
  1144. X    }
  1145. X    }
  1146. X
  1147. X  if (*t) return 0;
  1148. X  return 1;
  1149. X}
  1150. X
  1151. X/* Like glob_match, but match PATTERN against any final segment of TEXT.  */
  1152. X
  1153. static int
  1154. star_glob_match (pattern, text)
  1155. X     char *pattern, *text;
  1156. X{
  1157. X  register char *p = pattern, *t = text;
  1158. X  register char c, c1;
  1159. X
  1160. X  while ((c = *p++) == '?' || c == '*')
  1161. X    {
  1162. X      if (c == '?' && *t++ == 0)
  1163. X    return 0;
  1164. X    }
  1165. X
  1166. X  if (c == 0)
  1167. X    return 1;
  1168. X
  1169. X  if (c == '\\') c1 = *p;
  1170. X  else c1 = c;
  1171. X
  1172. X  for (;;)
  1173. X    {
  1174. X      if ((c == '[' || *t == c1)
  1175. X          && glob_match (p - 1, t, 0))
  1176. X    return 1;
  1177. X      if (*t++ == 0) return 0;
  1178. X    }
  1179. X}
  1180. END_OF_FILE
  1181. if test 7660 -ne `wc -c <'perms/glob_match.c'`; then
  1182.     echo shar: \"'perms/glob_match.c'\" unpacked with wrong size!
  1183. fi
  1184. # end of 'perms/glob_match.c'
  1185. fi
  1186. if test -f 'perms/perms.y' -a "${1}" != "-c" ; then 
  1187.   echo shar: Will not clobber existing file \"'perms/perms.y'\"
  1188. else
  1189. echo shar: Extracting \"'perms/perms.y'\" \(7791 characters\)
  1190. sed "s/^X//" >'perms/perms.y' <<'END_OF_FILE'
  1191. X/* Copyright (c) 1990 Theo de Raadt deraadt@cpsc.ucalgary.ca
  1192. X * All rights reserved.
  1193. X *
  1194. X * Redistribution and use in source and binary forms are permitted
  1195. X * provided that the above copyright notice and this paragraph are
  1196. X * duplicated in all such forms and that any documentation,
  1197. X * advertising materials, and other materials related to such
  1198. X * distribution and use acknowledge that the software was developed
  1199. X * by Theo de Raadt.
  1200. X */
  1201. X%{
  1202. X#ifndef lint
  1203. char Copyright[] =
  1204. X"@(#) Copyright (c) 1990 Theo de Raadt.\nAll rights reserved.\n";
  1205. X#endif not lint
  1206. X
  1207. X#ifndef lint
  1208. static    char Sccsid[] = "@(#)perms.y 1.0 90/11/01 TDR";
  1209. X#endif not lint
  1210. X
  1211. X#include <sys/param.h>
  1212. X#include <sys/types.h>
  1213. X#include <sys/socket.h>
  1214. X#include <sys/file.h>
  1215. X#include <netinet/in.h>
  1216. X#include <stdio.h>
  1217. X#include <ctype.h>
  1218. X#include <string.h>
  1219. X#include <pwd.h>
  1220. X#include <grp.h>
  1221. X#include <rpc/types.h>
  1222. X#include <rpc/rpc.h>
  1223. X#include <rpcsvc/ypclnt.h>
  1224. X#include <rpcsvc/yp_prot.h>
  1225. X#include <syslog.h>
  1226. X#include "y.tab.h"
  1227. X
  1228. X#undef DEBUG
  1229. X
  1230. X/* define SECURE if you want logins disallowed if errors show up
  1231. X * during a map lookup. If this is not set, YP failures, incorrect
  1232. X * maps, automount failure, etc.,will let anymore login until the
  1233. X * problem is fixed. In general, you never want to define this!
  1234. X */
  1235. X#undef    SECURE
  1236. X
  1237. X#define SEARCHMAP "permissions"
  1238. X
  1239. X#define LX_SP    0x00
  1240. X#define LX_EOF    0x01
  1241. X#define LX_C    0x02
  1242. X#define LX_X    0x04
  1243. X#define LX_SC    0x08
  1244. X#define LX_S1    0x10
  1245. static char lookup[] = {
  1246. X    0x01, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,     /* 00-07 */
  1247. X    0x04, 0x00, 0x01, 0x04, 0x04, 0x01, 0x04, 0x04,     /* 08-0f */
  1248. X    0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,     /* 10-17 */
  1249. X    0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,     /* 18-1f */
  1250. X    0x00, 0x02, 0x04, 0x04, 0x02, 0x04, 0x02, 0x04,     /* 20-27 */
  1251. X    0x18, 0x18, 0x18, 0x02, 0x02, 0x0a, 0x18, 0x18,     /* 28-2f */
  1252. X    0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,     /* 30-37 */
  1253. X    0x18, 0x18, 0x02, 0x04, 0x04, 0x04, 0x04, 0x18,     /* 38-3f */
  1254. X    0x02, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,     /* 40-47 */
  1255. X    0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,     /* 48-4f */
  1256. X    0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,     /* 50-57 */
  1257. X    0x18, 0x18, 0x18, 0x18, 0x04, 0x18, 0x18, 0x18,     /* 58-5f */
  1258. X    0x04, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,     /* 60-67 */
  1259. X    0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,     /* 68-6f */
  1260. X    0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,     /* 70-77 */
  1261. X    0x18, 0x18, 0x18, 0x04, 0x02, 0x04, 0x04, 0x04,     /* 78-7f */
  1262. X};
  1263. X
  1264. X#define YYSTYPE caddr_t
  1265. extern YYSTYPE yylval;
  1266. X
  1267. static char *grplst[NGROUPS], **grplist;
  1268. char domain[MAXHOSTNAMELEN], key[MAXHOSTNAMELEN];
  1269. static char *usern, *ttyn, *line;
  1270. static int ttymatch, grpusrmatch;
  1271. X
  1272. static int allow, err_allow;
  1273. static char *stack[20];
  1274. static int stackp;
  1275. X
  1276. static
  1277. yyerror() {
  1278. X    syslog(LOG_CRIT,
  1279. X        "permissions: [key %s] parsing error\n", key);
  1280. X    err_allow = 1;
  1281. X}
  1282. X
  1283. X/*
  1284. X * noisy, specifies to be noisy on failure or not
  1285. X */
  1286. static char *
  1287. getypent(s, noisy)
  1288. char *s;
  1289. X{
  1290. X    char *entry;
  1291. X    int entrylen, err;
  1292. X
  1293. X    err = yp_match(domain, SEARCHMAP, s, strlen(s), &entry, &entrylen);
  1294. X    if(err) {
  1295. X        if(noisy) syslog(LOG_CRIT,
  1296. X            "yperr: [key %s] %s\n", s, yperr_string(err));
  1297. X        return NULL;
  1298. X    }
  1299. X    return entry;
  1300. X}
  1301. X
  1302. X/* usr:  user name. Absolutely has to be the login name.
  1303. X * tty:  tty name. if NULL, any tty will match.
  1304. X * grps: NULL terminated array of group names. If grps==NULL, perms
  1305. X *     will fetch the groups using getpwent() and getgrent(). These
  1306. X *     have static data -- beware.
  1307. X * lkey: base lookup key. If NULL, hostname will be used.
  1308. X *
  1309. X * return values need cleaning up.
  1310. X *  1 - allowed
  1311. X *  0 - not allowed
  1312. X * -1 - error
  1313. X */
  1314. int
  1315. permcheck(usr, tty, grps, lkey)
  1316. char *usr, *tty, **grps, *lkey;
  1317. X{
  1318. X    struct passwd *pwd;
  1319. X    struct group *grp;
  1320. X    int ngrps = 0;
  1321. X
  1322. X    if(!usr)
  1323. X        return -1;
  1324. X    if(!grps) {
  1325. X        grps = grplst;
  1326. X#ifdef DEBUG
  1327. X        printf("user: %s\n", usr);
  1328. X#endif
  1329. X        setpwent();
  1330. X        if( !(pwd=getpwnam(usr)))
  1331. X            return -1;
  1332. X#ifdef DEBUG
  1333. X        printf("user: (%s)\n", pwd->pw_name);
  1334. X#endif
  1335. X
  1336. X        setgrent();
  1337. X        if( !(grp=getgrgid(pwd->pw_gid)) )
  1338. X            return -1;
  1339. X        *grps++ = strdup(grp->gr_name);
  1340. X#ifdef DEBUG
  1341. X        printf("group: %s\n", grp->gr_name);
  1342. X#endif
  1343. X        ngrps++;
  1344. X        while( grp=getgrent() ) {
  1345. X            if(pwd->pw_gid == grp->gr_gid)
  1346. X                continue;
  1347. X            while(*grp->gr_mem) {
  1348. X                if(!strcmp(*grp->gr_mem, usr)) {
  1349. X                    if(++ngrps>NGROUPS)
  1350. X                        break;
  1351. X                    *grps++ = strdup(grp->gr_name);
  1352. X#ifdef DEBUG
  1353. X                    printf("group: %s\n", grp->gr_name);
  1354. X#endif
  1355. X                }
  1356. X                grp->gr_mem++;
  1357. X            }
  1358. X        }
  1359. X        endgrent();
  1360. X        endpwent();
  1361. X        *grps = NULL;
  1362. X        grps = grplst;
  1363. X    }
  1364. X    if(lkey)
  1365. X        strcpy(key, lkey);
  1366. X    else
  1367. X        gethostname(key, sizeof key);
  1368. X
  1369. X    getdomainname(domain, sizeof domain);
  1370. X    if( !(line=getypent(key, 0)) ) {
  1371. X        line = getypent("*", 1);
  1372. X    }
  1373. X    allow = 0;
  1374. X    err_allow = !line;
  1375. X
  1376. X    if(line) {
  1377. X        usern = usr;
  1378. X        ttyn = tty;
  1379. X        grplist = grps;
  1380. X        ttymatch = grpusrmatch = -1;
  1381. X        yyparse();
  1382. X    }
  1383. X
  1384. X#ifdef SECURE
  1385. X    return allow;
  1386. X#else
  1387. X    return allow | err_allow;
  1388. X#endif
  1389. X}
  1390. X
  1391. static
  1392. newmap(s)
  1393. char *s;
  1394. X{
  1395. X#ifdef DEBUG
  1396. X    printf("include %s, pushing %s", s, line);
  1397. X#endif
  1398. X    stack[stackp++] = line;
  1399. X    if(stackp==sizeof(stack)/sizeof(char *)) {
  1400. X        syslog(LOG_CRIT,
  1401. X            "permissions: stack overflow on [key %s]\n", s);
  1402. X        line = stack[--stackp];
  1403. X        err_allow = 1;
  1404. X        return;
  1405. X    }
  1406. X    line = getypent(s,1);
  1407. X    if(!line) {
  1408. X        syslog(LOG_CRIT,
  1409. X            "permissions: [key %s] not found\n", s);
  1410. X        line = stack[--stackp];
  1411. X        err_allow = 1;
  1412. X        return;
  1413. X    }
  1414. X#ifdef DEBUG
  1415. X    printf("result %s", line);
  1416. X#endif
  1417. X}
  1418. X
  1419. static
  1420. yylex()
  1421. X{
  1422. X    static pos = 0;
  1423. X    static char savebuf[1024], *p;
  1424. X    char c;
  1425. X
  1426. restartlex:
  1427. X    p = savebuf;
  1428. X    while(1)
  1429. X        switch( lookup[(c= *line++)] ) {
  1430. X        case LX_SP:
  1431. X            break;
  1432. X        case LX_EOF:
  1433. X            if(!stackp)
  1434. X                return -1;
  1435. X            line = stack[--stackp];
  1436. X#ifdef DEBUG
  1437. X            printf("popping %s", line);
  1438. X#endif
  1439. X            goto restartlex;
  1440. X        case LX_C:
  1441. X        case LX_C|LX_SC:
  1442. X#ifdef DEBUG
  1443. X            printf("lex: char '%c'\n", c);
  1444. X#endif
  1445. X            return c;
  1446. X        case LX_X:
  1447. X            syslog(LOG_CRIT,
  1448. X                "permissions: [key %s] illegal char 0%3o\n",
  1449. X                key, c);
  1450. X            err_allow = 1;
  1451. X            return -1;
  1452. X        case LX_S1:
  1453. X        case LX_S1|LX_SC:
  1454. X            do {
  1455. X                *p++ = c;
  1456. X                c = *line++;
  1457. X            } while( lookup[c]&LX_SC );
  1458. X            *p = '\0';
  1459. X            line--;
  1460. X            yylval = savebuf;
  1461. X#ifdef DEBUG
  1462. X            printf("lex: symbol %s\n", savebuf);
  1463. X#endif
  1464. X            return SYMBOL;
  1465. X        }
  1466. X}
  1467. X
  1468. static void
  1469. grpcheck(s, add)
  1470. char *s;
  1471. X{
  1472. X    FILE *fin;
  1473. X    char **grp, *p, buf[80];
  1474. X    int i;
  1475. X
  1476. X    switch(*s) {
  1477. X    case '(':
  1478. X        if( strchr(s+1, '(')) {
  1479. X            syslog(LOG_CRIT,
  1480. X                "permissions: [key %s] can't nest brackets\n", s);
  1481. X            return;
  1482. X        }
  1483. X
  1484. X        p = strchr(s, ')');
  1485. X        if(p)
  1486. X            *p = '\0';
  1487. X        else {
  1488. X            syslog(LOG_CRIT,
  1489. X                "permissions: [key %s] include syntax error\n", s);
  1490. X            return;
  1491. X        }
  1492. X        if( strchr(s, ')')) {
  1493. X            syslog(LOG_CRIT,
  1494. X                "permissions: [key %s] can't nest brackets\n", s);
  1495. X            return;
  1496. X        }
  1497. X
  1498. X        s++;
  1499. X        fin = fopen(s, "r");
  1500. X        if(!fin) {
  1501. X            syslog(LOG_CRIT,
  1502. X                "permissions: [key %s] can't open include\n", s);
  1503. X            return;
  1504. X        }
  1505. X        while( fgets(buf, sizeof buf, fin) ) {
  1506. X            for(p=buf; *p; p++)
  1507. X                if( *p==' ' || *p=='\n' || *p=='#' || *p=='\t' ) {
  1508. X                    *p = '\0';
  1509. X                    break;
  1510. X                }
  1511. X            if(!*buf)
  1512. X                continue;
  1513. X#ifdef DEBUG
  1514. X            printf("file: %s '%s'\n", s, buf);
  1515. X#endif
  1516. X            grpcheck(buf, add);
  1517. X        }
  1518. X        fclose(fin);
  1519. X        break;
  1520. X    case '.':
  1521. X        grp = grplist;
  1522. X        while(*grp) {
  1523. X            if( glob_match(s+1, *grp, 0) )
  1524. X                grpusrmatch = add;
  1525. X            grp++;
  1526. X        }
  1527. X        break;
  1528. X    default:
  1529. X        if( !strcmp(s, usern) )
  1530. X            grpusrmatch = add;
  1531. X        break;
  1532. X    }
  1533. X}
  1534. X
  1535. X%}
  1536. X
  1537. X%token SYMBOL
  1538. X%start permlist
  1539. X
  1540. X%%
  1541. permlist    : perm
  1542. X        | permlist '|' perm
  1543. X        ;
  1544. X
  1545. perm        : ttylist ':' grouplist {
  1546. X            if(ttymatch!=-1 && grpusrmatch!=-1)
  1547. X                allow = ttymatch && grpusrmatch;
  1548. X            ttymatch = grpusrmatch = -1;
  1549. X        }
  1550. X        | '$' SYMBOL { newmap($2); } permlist
  1551. X        |
  1552. X        ;
  1553. X
  1554. ttylist        : tty
  1555. X        | ttylist ',' tty
  1556. X        ;
  1557. grouplist    : group
  1558. X        | grouplist ',' group
  1559. X        ;
  1560. X
  1561. tty        : SYMBOL {
  1562. X            if(!ttyn)
  1563. X                ttymatch = 1;
  1564. X            else if( glob_match($1, ttyn, 0) )
  1565. X                ttymatch = 1;
  1566. X        }
  1567. X        ;
  1568. X
  1569. group        : '+' SYMBOL    { grpcheck($2, 1); }
  1570. X        | '-' SYMBOL    { grpcheck($2, 0); }
  1571. X        ;
  1572. X%%
  1573. END_OF_FILE
  1574. if test 7791 -ne `wc -c <'perms/perms.y'`; then
  1575.     echo shar: \"'perms/perms.y'\" unpacked with wrong size!
  1576. fi
  1577. # end of 'perms/perms.y'
  1578. fi
  1579. if test ! -d 'permtest' ; then
  1580.     echo shar: Creating directory \"'permtest'\"
  1581.     mkdir 'permtest'
  1582. fi
  1583. if test -f 'permtest/Makefile' -a "${1}" != "-c" ; then 
  1584.   echo shar: Will not clobber existing file \"'permtest/Makefile'\"
  1585. else
  1586. echo shar: Extracting \"'permtest/Makefile'\" \(164 characters\)
  1587. sed "s/^X//" >'permtest/Makefile' <<'END_OF_FILE'
  1588. OBJ = permtest.o ../perms/perms.o ../perms/glob_match.o
  1589. CFLAGS = -g -DPERMS
  1590. X
  1591. permtest:    $(OBJ)
  1592. X        $(CC) $(LDFLAGS) $(OBJ) -o permtest
  1593. X
  1594. clean:
  1595. X        $(RM) *~ *.o permtest
  1596. END_OF_FILE
  1597. if test 164 -ne `wc -c <'permtest/Makefile'`; then
  1598.     echo shar: \"'permtest/Makefile'\" unpacked with wrong size!
  1599. fi
  1600. chmod +x 'permtest/Makefile'
  1601. # end of 'permtest/Makefile'
  1602. fi
  1603. if test -f 'permtest/permtest.c' -a "${1}" != "-c" ; then 
  1604.   echo shar: Will not clobber existing file \"'permtest/permtest.c'\"
  1605. else
  1606. echo shar: Extracting \"'permtest/permtest.c'\" \(1614 characters\)
  1607. sed "s/^X//" >'permtest/permtest.c' <<'END_OF_FILE'
  1608. X#include <sys/param.h>
  1609. X#include <sys/types.h>
  1610. X#include <sys/socket.h>
  1611. X#include <string.h>
  1612. X#include <stdio.h>
  1613. X#include <ctype.h>
  1614. X#include <netdb.h>
  1615. X#include <grp.h>
  1616. X#include <pwd.h>
  1617. X
  1618. char *grpnames[NGROUPS+1];
  1619. int ngrps;
  1620. struct passwd *pwd;
  1621. struct group *grp;
  1622. int verbose;
  1623. X
  1624. extern int permcheck();
  1625. X
  1626. main(argc, argv)
  1627. char **argv;
  1628. X{
  1629. X    char *logn, *ttyn, *hostn;
  1630. X    struct hostent *hent;
  1631. X    int lp, i;
  1632. X
  1633. X    if(argc<4) {
  1634. X        fprintf(stderr, "usage: %s [-v] username ttyname hostname\n",
  1635. X            *argv);
  1636. X        exit(0);
  1637. X    }
  1638. X    if(!strcmp(argv[1], "-v")) {
  1639. X        argv++;
  1640. X        verbose=1;
  1641. X    }
  1642. X
  1643. X    logn = argv[1];
  1644. X    ttyn = argv[2];
  1645. X
  1646. X    setpwent();
  1647. X    pwd = getpwnam(logn);
  1648. X    if(!pwd) {
  1649. X        fprintf(stderr, "%s: unknown user\n", logn);
  1650. X        exit(0);
  1651. X    }
  1652. X
  1653. X    setgrent();
  1654. X    ngrps = 0;
  1655. X    if(!(grp=getgrgid(pwd->pw_gid))) {
  1656. X        fprintf(stderr, 
  1657. X            "%d: group id has no name\n", pwd->pw_gid);
  1658. X        exit(0);
  1659. X    }
  1660. X    grpnames[ngrps++] = strdup(grp->gr_name);
  1661. X    while( grp=getgrent() ) {
  1662. X        if(pwd->pw_gid == grp->gr_gid)
  1663. X            continue;
  1664. X        while(*grp->gr_mem) {
  1665. X            if( !strcmp(logn, *grp->gr_mem)) {
  1666. X                grpnames[ngrps++] = strdup(grp->gr_name);
  1667. X            }
  1668. X            grp->gr_mem++;
  1669. X        }
  1670. X    }
  1671. X    endgrent();
  1672. X    grpnames[ngrps] = NULL;
  1673. X
  1674. X    if(verbose) {
  1675. X        printf("%d group%s:", ngrps, (ngrps>1)?"s":"");
  1676. X        for(i=0; i<ngrps; i++)
  1677. X            printf(" %s", grpnames[i]);
  1678. X        printf("\n");
  1679. X    }
  1680. X
  1681. X    for( argv= &argv[3]; *argv; argv++) {
  1682. X        if((hent = gethostbyname(*argv)))
  1683. X            hostn = hent->h_name;
  1684. X        else
  1685. X            hostn = *argv;
  1686. X        lp = permcheck(logn, ttyn, grpnames, hostn);
  1687. X        if(verbose)
  1688. X            printf("user %s %spermitted on %s:%s\n",
  1689. X                logn, lp ? "":"not ", hostn, ttyn);
  1690. X        else
  1691. X            printf("%s: %s\n", hostn, lp ? "":"not");
  1692. X    }
  1693. X    exit(0);
  1694. X}
  1695. X
  1696. X
  1697. X
  1698. END_OF_FILE
  1699. if test 1614 -ne `wc -c <'permtest/permtest.c'`; then
  1700.     echo shar: \"'permtest/permtest.c'\" unpacked with wrong size!
  1701. fi
  1702. # end of 'permtest/permtest.c'
  1703. fi
  1704. echo shar: End of archive 1 \(of 3\).
  1705. cp /dev/null ark1isdone
  1706. MISSING=""
  1707. for I in 1 2 3 ; do
  1708.     if test ! -f ark${I}isdone ; then
  1709.     MISSING="${MISSING} ${I}"
  1710.     fi
  1711. done
  1712. if test "${MISSING}" = "" ; then
  1713.     echo You have unpacked all 3 archives.
  1714.     rm -f ark[1-9]isdone
  1715. else
  1716.     echo You still need to unpack the following archives:
  1717.     echo "        " ${MISSING}
  1718. fi
  1719. ##  End of shell archive.
  1720. exit 0
  1721.  
  1722.